package utils;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;


//Object代理类
//不管 被代理类有多少方法 方法是任意返回值都可以代理
//比静态代理有更强的扩展性
public class DlProxy implements InvocationHandler {
    private Object delegate;

    public Object bind(Object delegate) {
        this.delegate = delegate;
        return Proxy.newProxyInstance(
                this.delegate.getClass().getClassLoader(), this.delegate
                        .getClass().getInterfaces(), this);
    }

    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        Object result = null;
        try {
            System.out.println("befor...");
            // JVM通过这条语句执行原来的方法(反射机制)
            result = method.invoke(this.delegate, args);
            System.out.println("after...");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return result;
    }


    /*理论上只需要 被代理类的全类名       反射创建对象
    *            被代理类实现的接口
    * 就能完成动态代理
    * 而且很多代码是写死的
    * 只需要改动invoke方法中的  代理业务逻辑就行了*/



    /*缺点：
1）代理对象的一个接口只服务于一种类型的对象，如果要代理的方法很多，势必要为每一种方法都进行代理，静态代理在程序规模稍大时就无法胜任了。
2）如果接口增加一个方法，除了所有实现类需要实现这个方法外，所有代理类也需要实现此方法。增加了代码维护的复杂度。

三、动态代理
动态代理类的源码是在程序运行期间由JVM根据反射等机制动态的生成，所以不存在代理类的字节码文件。代理类和委托类的关系是在程序运行时确定。 */

    public static void main(String[] args) {
        //获取代理类对象
        DlProxy dlProxy = new DlProxy();
        Class clazz= null;
        try {

            //感觉这个 比静态代理要高级一点
            Demo01 demo01 = new Demo01();
            Eat o2 =(Eat)  dlProxy.bind(demo01);
            o2.eat();


            //动态代理类 与静态代理类对照的是动态代理类,
            // 动态代理类的字节码在程序运行时由Java反射机制动态生成,无需程序员手工编写它的源代码
            clazz = Class.forName("utils.Demo01");
            Object o = clazz.newInstance();
            Eat o1 =(Eat) dlProxy.bind(o);

            //o1其实是实现了接口的代理类对象   但是是通过Proxy.newProxyInstance获取的
            //不深究源码的情况下   猜测代理类实现InvocationHandler接口的作用就是
            // 代理类执行方法时都会转到  invoke方法中执行
            o1.eat();
        } catch (Exception e) {
            e.printStackTrace();
        }


    }

}